package  org.osami.commons.smarthome.settopbox.impl;

import java.io.*;
import java.net.*;
import java.util.Hashtable;
import java.util.StringTokenizer;
import java.util.Timer;
import java.util.TimerTask;

import org.kxml.*;
import org.kxml.parser.*;

import org.osami.commons.smarthome.settopbox.ISetTopBoxComponent;

public class SetTopBoxComponent implements ISetTopBoxComponent {
	
	//ServerSocket serverSocket;
	//Socket connectionSocket;
	DataOutputStream outStream;
	BufferedReader inStream;
	Thread initThread, receiverThread;
	boolean accepted = false;
	Timer timer;

	class fireTimeout extends TimerTask {
	public void run() {
		continuePlayback();
		timer.cancel(); //Terminate the timer thread
		}
	}


	public SetTopBoxComponent() {
		System.out.println("SetTopBoxComponent starting");
		
		// This is a hard-coded "Putki-Lassi" for WebRemoteController... :D
		String reply = handleRequest("http://localhost/web/vol"); // Just asks the current volume level
		System.out.println(reply);
		/*
		try {
			
			serverSocket = new ServerSocket(6787);
	        
			initThread = new Thread() {
			
				public void run() {
					
					while (true) {
					
						try {
							System.out.println("Initializing python connection socket");
							SetTopBoxComponent.this.connectionSocket = SetTopBoxComponent.this.serverSocket.accept();
							SetTopBoxComponent.this.inStream = new BufferedReader(new InputStreamReader(SetTopBoxComponent.this.connectionSocket.getInputStream()));
							SetTopBoxComponent.this.outStream = new DataOutputStream(SetTopBoxComponent.this.connectionSocket.getOutputStream());
							System.out.println("Connected to python");
							
							setAccepted(true);
							
							
							receiverThread = new Thread() {
						        	
					        	public void run() {
					        		System.out.println("ReceiverThread started");
					        		String line = null;
					        		
					        		do {
					        			try {
					        				line = SetTopBoxComponent.this.inStream.readLine();
											System.out.println("python > " + line);
										} catch (IOException e) {
											e.printStackTrace();
										}
					        		} while (null != line);
					        		
					        		try {
										connectionSocket.close();
									} catch (IOException e) {
										// TODO Auto-generated catch block
										e.printStackTrace();
									}
					        	}
					        	
					        };
						    
						    receiverThread.start();
						    
						    while (connectionSocket.isConnected()) {
						    	try {
									Thread.sleep(1000);
								} catch (InterruptedException e) {
									// TODO Auto-generated catch block
									e.printStackTrace();
								}
						    }
						    System.out.println("Connection lost, retrying...");
						    if (receiverThread.isAlive())
						    	receiverThread.stop();
							
						} catch (IOException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						} // try/catch
					} // while
				} // run

			};
	        
	        //clientSentence = inFromClient.readLine();
	        //System.out.println("Received: " + clientSentence);
	        //capitalizedSentence = clientSentence.toUpperCase() + '\n';
	        
	       
	        
	        initThread.start();
	        
	        
	         
		} catch (Exception ex) {
			System.out.println(ex.getMessage());
		}
		*/

	}
	
	protected void finalize() {
		System.out.println("Finalizing SetTopBoxComponent");
		try {
			//receiverThread.stop();
			//initThread.stop();
			
			//connectionSocket.close();
			//serverSocket.close();
			super.finalize();
		} catch (Throwable e) {
			e.printStackTrace();
		}
	}
	
	/**
	* Send a message to the TV screen through enigma2 Web interface
	* 
	* @param messagetext Text of Message
	* @param messagetype Number from 0 to 3, 0=Yes/No, 1=Info, 2=Message, 3=Attention
	* @param timeout Can be empty or the Number of seconds the Message should disappear after.
	*
	*/
	public void SendMessage(String messagetext, int messagetype, int timeout) {
					
	    // Encoding messagetext
		String endocedMessagetext = URLEncoder.encode(messagetext);
			
		handleRequest("http://localhost/web/message?text="+endocedMessagetext+"&type="+messagetype+"&timeout="+timeout);
								
	}
	
	/**
	* Receive message from enigma2 plugin
	*
	*/
	public String ReceiveMessage()
	{
		return "";
	}

	/**
	* Set mute on/off
	*
	*/
	public void setMute() {
		handleRequest("http://localhost/web/vol?set=mute");
		
	}

	/**
	* Set volume to the desired level
	*
	*/
	public void setVolume(String volume) {
		handleRequest("http://localhost/web/vol?set="+volume);
		
	}
	
	/**
	* Get current volume
	*
	* @return volume number of volume level between 0-100 as a String
	*/
	public String getCurrentVolume() {
		String volume = "-1";
		String reply = handleRequest("http://localhost/web/vol");
		InputStream is = new ByteArrayInputStream( reply.getBytes() );
		//System.out.println("ProgramDatabase: programList "+programList.get(programName));
		try {
			volume = this.MyXmlParser(reply, "e2current");	
		}
		catch (Exception ex) {
			System.out.println("Error in getCurrentVolume: " + ex.getMessage());
			ex.printStackTrace();
		}
		System.out.println("SetTopBoxComponent.getCurrentVolume: volume="+volume);
		return volume;
		
	}
	
	/**
	* Pauses playback
	*
	*/
	public void pausePlayback()
	{
		//sendString("Pause");
		
		sendRemoteControlRequest(400); // 400 Key "yellow"

	}


	/**
	* Continues playback
	*
	*/
	public void continuePlayback()
	{
		//sendString("Play");
		sendRemoteControlRequest(352); // 352 Key "ok"
		sendRemoteControlRequest(399); // 399 Key "green"	
	}

	/**
	* Forward
	*
	*/
	public void forwardPlayback()
	{
		//sendString("Forward");
		
		sendRemoteControlRequest(401); // 401 Key "blue"
	
	}
	
	/**
	* Stop timeshift
	*
	*/
	public void stopTimeshift(){
		sendRemoteControlRequest(377); // 377 Key "tv" or "stop"
		sendRemoteControlRequest(352); // 352 Key "ok"
	}
	
	/**
	* Shows incoming call info on screen
	*
	*/	
	public void receiveCall(String caller, String phoneNumber)
	{
		//sendString("Call, " + caller + ", " + phoneNumber);
		
		// Jos ollaan Dreamboxin jossakin alavalikossa, niin pakko päästä pois että pausetus toimii.
		// Tämä käytännössä käskyttää 5 kertaa remote controllin exit-nappia.
		// Olisko tähän jotain muuta keinoa? Vai tarviiko ollakkaan?
		/*
		for ( i=1; i<6; i++ ) {
			handleRequest("http://localhost/web/remotecontrol?command=174");
		}
		*/
		
		pausePlayback();

		String messagetext = "Incoming Call\n\nCaller: "+caller + "\nPhonenumber: " + phoneNumber;
		int messagetype = 1;
		int timeout = 10;
		SendMessage(messagetext, messagetype, timeout);
						
	}
	
	/**
	* Shows Text message info on TV screen
	*
	*/	
	public void receiveTextMessage(String sender, String phoneNumber, String msg)
	{
		//sendString("TextMessage, " + sender + ", " + phoneNumber + ", " + msg);
		
		// Jos ollaan Dreamboxin jossakin alavalikossa, niin pakko päästä pois että pausetus toimii.
		// Tämä käytännössä käskyttää 5 kertaa remote controllin exit-nappia.
		// Olisko tähän jotain muuta keinoa? Vai tarviiko ollakkaan?
		/*
		for ( i=1; i<6; i++ ) {
			handleRequest("http://localhost/web/remotecontrol?command=174");
		}
		*/

		pausePlayback();

		String messagetext = "SMSMessage\n\nSender: "+sender + "\nPhonenumber: " + phoneNumber + "\nMessage: "+msg;
		int messagetype = 1;
		int timeout = 15;
		SendMessage(messagetext, messagetype, timeout);
		timer = new Timer();
		timer.schedule(new fireTimeout(), timeout*1000);
	}
	
	
	/**
	* Change channel up
	*
	*/
	public void changeChannelUp()
	{
		//sendString("ChannelUp");
		
		sendRemoteControlRequest(106); // 106 Key "right"
	}
	
	/**
	* Change channel down
	*
	*/
	public void changeChannelDown()
	{
		//sendString("ChannelDown");
		
		sendRemoteControlRequest(105); // 105 Key "left"
	}
	
	/**
	* Get current channel
	*
	*/
	public String getCurrentChannel() {
		String channel = "";
		String program = "";
		String reply = handleRequest("http://localhost/web/getcurrent");
		
		//System.out.println("ProgramDatabase: programList "+programList.get(programName));
		try {
			channel = this.MyXmlParser(reply, "e2eventservicename");
			program = this.MyXmlParser(reply, "e2eventname");
		}
		catch (Exception ex) {
			System.out.println("Error in getCurrentChannel: " + ex.getMessage());
			ex.printStackTrace();
		}
		if (channel.length() > 0)
		{
			try{
				StringTokenizer token = new StringTokenizer(channel, ","); 
				System.out.println("SetTopBoxComponent.getCurrentChannel: current channel="+token.nextToken() );
			}
			catch (Exception e) {
				System.out.println("Error while tokenizing:" + e.getMessage());
			}
			
		}
				
		if (program.length() > 0)
		{
			try{
				StringTokenizer token = new StringTokenizer(program, ","); 
				System.out.println("SetTopBoxComponent.getCurrentChannel: current program="+token.nextToken() );
				while (token.hasMoreElements())
				{
					System.out.println("SetTopBoxComponent.getCurrentChannel: next program="+token.nextToken() );
				}
			}
			catch (Exception e) {
				System.out.println("Error while tokenizing:" + e.getMessage());
			}
			
		}
		return channel;
	}
	
	/**
	* Schedules recording of an event
	*
	* @param eventId Id of the event to be recorded
	* @param serviceName A name of the service (channel name) containing the event
	*/
	public void scheduleEventRecord(int eventId, String serviceRef)
	{
		//sendString("RecordEvent, " + eventId + ", " + serviceRef);
		//SendMessage("RecordEvent, " + eventId + ", " + serviceRef);
			
		// Finally add a timer to the specific event
		
		handleRequest("http://localhost/web/timeraddbyeventid?sRef="+serviceRef+"&eventid="+eventId+"&justplay=0");
		
	}
	
	/**
	* Get all Services
	*
	*/
	public void getAllServices()
	{				
		handleRequest("http://localhost/web/getservices?sRef=1:7:1:0:0:0:0:0:0:0:FROM%20BOUQUET%20%22userbouquet.favourites.tv%22%20ORDER%20BY%20bouquet");
		
	}
	
	/**
	* Get Box General info
	*
	*/
	public void showBoxInfo()
	{				
		handleRequest("http://localhost/web/about");
		
	}
	
	/**
	* Search program by given search string.
	*
	* @param searchString The search string for the wanted program name
	* @return String reply The reply for the search as a String, formatted in XML.
	* 			See more details from https://dream.reichholf.net/wiki/Enigma2:WebInterface#EPG
	*/
	public String searchProgramByName(String searchString)
	{
		if (searchString.length()>=1)
		{
			System.out.println("SetTopBoxComponent: Finding program by name "+searchString);
			String endocedString = "";
			// Encoding search text
			try
			{
				endocedString = URLEncoder.encode(searchString);
			}
			catch(Exception uee){
				System.err.println(uee);
			}
				
			// Send search request to enigma2 web interface
			String reply = handleRequest("http://localhost/web/epgsearch?search="+endocedString);
			return reply;
		}
		return null;
	}
	
	/**
	* Add a TV program name into the list of interesting programs
	* 
	* @param programName The name of the program
	* @param imeiCode The imei code of the user's mobile device
	* @throws IOException 
	*
	*/
	public String addInterestingProgram(String programName, String imeiCode) throws IOException {
		
		String oldList="";
		String newLine="";
		String newList="";
		try{
			// At first, read an old programList
			FileReader fr = new FileReader("/media/hdd/programList.xml");
			BufferedReader br = new BufferedReader(fr);
			while((newLine = br.readLine()) != null) {
				oldList = oldList+newLine+"\n"; 				
			}
			fr.close();
					
			// Then add a new program into the list
			newList = oldList.replaceAll("</database>", "\t<keyWord deviceId=\""+imeiCode+"\" programName=\""+programName+"\"></keyWord>\n</database>");
			FileWriter fstream = new FileWriter("/media/hdd/programList.xml");
			BufferedWriter out = new BufferedWriter(fstream);
			out.write(newList);
			//Close the output stream
			out.close();
			System.out.println("Program "+programName+" added into the "+imeiCode+"'s list!");
		}
		catch (Exception e) {
			System.out.println(e);
		}
		return newList;
	}

	/**
	* Remove a TV program name from the list of interesting programs
	* 
	* @param programName The name of the program
	* @param imeiCode The imei code of the user's mobile device
	* @throws IOException 
	*
	*/
	public String removeInterestingProgram(String programName, String imeiCode) throws IOException {
		String oldList="";
		String newLine="";
		try{
			// At first, read an old programList
			FileReader fr = new FileReader("/media/hdd/programList.xml");
			BufferedReader br = new BufferedReader(fr);
			while((newLine = br.readLine()) != null) {
				if(newLine.contains(imeiCode) && newLine.contains(programName))
					System.out.println("Program "+programName+" removed from the "+imeiCode+"'s list!");
				else
					oldList = oldList+newLine+"\n"; 				
			}
			fr.close();
			
			// Then add a new program into the list
			FileWriter fstream = new FileWriter("/media/hdd/programList.xml");
			BufferedWriter out = new BufferedWriter(fstream);
			out.write(oldList);
			//Close the output stream
			out.close();
			
		}
		catch (Exception e) {
			System.out.println(e);
		}
		return oldList;
	}
	
	/**
	* Toggle Standby
	*
	*/
	public void toggleStandby()
	{		
		sendRemoteControlRequest(116); // 116 Key "Power"
	}
	
	
	/**
	* Sends HTTP Request to the Dreambox Web API
	* Uses the enigma2 Web API: ***https://dream.reichholf.net/wiki/Enigma2:WebInterface#Client_API***
	* 
	* @param command Integer corresponding the key in remote control as follows:
	* 116 Key "Power"	
	* 2   Key "1"	 
	* 3   Key "2"	
	* 4   Key "3"	
	* 5   Key "4"	
	* 6   Key "5"	
	* 7   Key "6"	
	* 8   Key "7"	
	* 9   Key "8"	
	* 10  Key "1"	
	* 11  Key "0"	
	* 412 Key "previous"	
	* 407 Key "next	
	* 115 Key "volume up"	
	* 113 Key "mute"	
	* 402 Key "bouquet up"	
	* 114 Key "volume down"	
	* 174 Key "lame"	
	* 403 Key "bouquet down"	
	* 358 Key "info"	
	* 103 Key "up"	
	* 139 Key "menu"	
	* 105 Key "left"	
	* 352 Key "OK"	
	* 106 Key "right"	
	* 392 Key "audio"	
	* 108 Key "down"	
	* 393 Key "video"	
	* 398 Key "red"	
	* 399 Key "green"	
	* 400 Key "yellow"	
	* 401 Key "blue"	
	* 377 Key "tv"	
	* 385 Key "radio"	
	* 388 Key "text"	
	* 138 Key "help"
	*
	*/
	private void sendRemoteControlRequest(int command)
	{	
		handleRequest("http://localhost/web/remotecontrol?command="+command);

	}
	
	/**
	* Handle enigma2 web API requests
	*
	*/
	private String handleRequest(String request)
	{	
		String reply="";
		String thisLine="";
		try
		{
			// Send data to enigma2 web interface
			URL url = new URL(request);
			URLConnection conn = url.openConnection();
	
			// Get the response
			BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
			
			while ((thisLine = rd.readLine()) != null) {
				//System.out.println(reply);
				reply = reply + thisLine + "\n";
			}
			
			rd.close();
			return reply;
		}
		catch (Exception e) {
			System.out.println(e);
		}
		return reply;
	}

	private String MyXmlParser (String reply, String keyword) throws IOException{
		
		InputStream is = new ByteArrayInputStream( reply.getBytes() );
		XmlParser parser = new XmlParser(new InputStreamReader(is));
		ParseEvent event = null;
		String currentElement = "";
		String value ="empty";
				
		//System.out.println("SetTopBoxComponent: MyXMLParser starts");
		while((event = parser.read()).getType() != Xml.END_DOCUMENT){
			
			if(event.getType() == Xml.START_TAG){
				currentElement = event.getName();
				//System.out.println(currentElement);
				
				if (currentElement.equals(keyword)) {
					ParseEvent next = parser.read();
					if (next.getType() != Xml.END_TAG )
					{
						if (value.equals("empty") )
							value = next.getText().trim();
						else
							value =  value +","+ next.getText().trim();
						
						//System.out.println(value);
					}
								
					currentElement = "";
				}
				
			}
			
			event = null;
		}
		parser = null;
		//System.out.println("SetTopBoxComponent: MyXMLParser is ready");
		return value;
	}




	
}